package main

import (
	"context"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
	"usercenter/config"
	"usercenter/interceptor"
	"usercenter/internal/cache"
	"usercenter/internal/discovery"
	"usercenter/internal/handler"
	"usercenter/internal/model"
	"usercenter/internal/service"
	"usercenter/middleware"
	"usercenter/routes"
	"usercenter/utils/logx"
)

// TODO api rpc 服务分离

func main() {
	// 组件初始化
	defer logx.InitLog()()
	config.InitConf()
	cache.InitCache()
	model.InitDB()

	// ==============================================  RPC Client 	==============================================
	// ----------------------------------------------    email 		----------------------------------------------
	discovery.DiscoverEmail()

	// ==============================================  RPC Server 	==============================================
	grpcServer := grpc.NewServer(grpc.ChainUnaryInterceptor(interceptor.LogInterceptor, interceptor.ErrInterceptor, interceptor.AuthInterceptor))
	service.RegisterUserServiceServer(grpcServer, &handler.UserService{})
	reflection.Register(grpcServer)
	// ==============================================  API Server 	==============================================
	ginRouter := gin.New()
	gin.SetMode(gin.DebugMode)
	//ginRouter.Use(middleware.LogMiddleware(), middleware.CorsMiddleware(), middleware.ErrorMiddleware())
	ginRouter.Use(middleware.LogMiddleware(), middleware.ErrorMiddleware())
	routes.InitRouter(ginRouter)
	// ===========================================================================================================

	// http-server handler
	flowHandler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		if request.ProtoMajor == 2 && strings.HasPrefix(request.Header.Get("Content-Type"), "application/grpc") {
			grpcServer.ServeHTTP(writer, request)
		} else {
			ginRouter.ServeHTTP(writer, request)
		}
	})
	// 禁用 TLS 加密协议
	h2Handler := h2c.NewHandler(flowHandler, &http2.Server{})

	// http-server config
	server := &http.Server{
		Addr:           "0.0.0.0:" + viper.GetString("server.port"),
		Handler:        h2Handler,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
		//BaseContext:    nil,
		//ConnContext:    nil,
	}

	// 优雅关闭
	go gracefulClose(server)

	// 监听 HTTP 服务
	logx.LogrusObj.Infoln("[SYSTEM] Server listen at", server.Addr)
	if err := server.ListenAndServe(); err != nil {
		// 自然关闭
		if err != http.ErrServerClosed {
			logx.LogrusObj.Fatalln(errors.Wrap(err, "[SYSTEM]"))
		}
	}
	logx.LogrusObj.Infoln("[SYSTEM] closing http server gracefully success")
}

func gracefulClose(server *http.Server) {
	register := discovery.RpcEtcdRegister("user")

	done := make(chan os.Signal, 1)
	signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
	<-done

	// 服务注销
	logx.LogrusObj.Infoln("[DISCOVERY] unregister rpc server ...")
	register.Stop()
	// 关闭发现
	discovery.EmailDiscover.Stop()
	// 关闭服务
	logx.LogrusObj.Infoln("[SYSTEM] closing http server gracefully ...")
	if err := server.Shutdown(context.TODO()); err != nil {
		logx.LogrusObj.Fatalln("[SYSTEM] closing http server gracefully failed: ", err)
	}
}
